package com.zdft.promotion.common.dao;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

/**
 * 抽象DAO实现
 */
public abstract class AbstractDAO
{
    /**
     * sql会话工厂
     */
    @Resource private SqlSessionFactory sqlSessionFactory;

    /**
     * 是否启用sql命名空间
     */
    private final boolean namespaceEnabled;

    /**
     * 批处理操作数据量，默认100/一组
     */
    private final int batchSize;

    private String namespace;

    public AbstractDAO(boolean namespaceEnabled)
    {
        this(namespaceEnabled, 100);
    }

    protected AbstractDAO(boolean namespaceEnabled, int batchSize)
    {
        this.namespaceEnabled = namespaceEnabled;
        this.batchSize = batchSize;
    }

    public int insert(String namingId, Object arg)
    {
        try (SqlSession session = sqlSessionFactory.openSession())
        {
            return session.insert(namingId(namingId), arg);
        }
    }

    /**
     * 物理删除操作
     * ！！！请根据实际业务谨慎操作！！！
     *
     * @param namingId sql命名ID
     * @param arg      入参
     * @return 操作结果
     */
    public int delete(String namingId, Object arg)
    {
        try (SqlSession session = sqlSessionFactory.openSession())
        {
            return session.delete(namingId(namingId), arg);
        }
    }

    public int update(String namingId, Object arg)
    {
        try (SqlSession session = sqlSessionFactory.openSession())
        {
            return session.update(namingId(namingId), arg);
        }
    }

    public <T> T selectOne(String namingId, Object arg)
    {
        try (SqlSession session = sqlSessionFactory.openSession())
        {
            return session.selectOne(namingId(namingId), arg);
        }
    }

    public <T> List<T> selectList(String namingId, Object arg)
    {
        try (SqlSession session = sqlSessionFactory.openSession())
        {
            return session.selectList(namingId(namingId), arg);
        }
    }

    public void batchExecute(String namingId, List<?> args, IBatchOperator operator)
    {
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH))
        {
            namingId = namingId(namingId);
            int len = args.size();
            for (int i = 0; i < len; i++)
            {
                operator.operate(session, namingId, args.get(i));
                if ((i + 1) % batchSize == 0)
                {
                    session.flushStatements();
                    session.commit();
                }
            }
            if (len % batchSize > 0)
            {
                session.flushStatements();
                session.commit();
            }
        }
    }

    public void batchInsert(String namingId, List<?> args)
    {
        batchExecute(namingId, args, SqlSession::insert);
    }

    /**
     * 物理批量删除操作
     * ！！！请根据实际业务谨慎操作！！！
     *
     * @param namingId sql命名ID
     * @param args     入参
     */
    public void batchDelete(String namingId, List<?> args)
    {
        batchExecute(namingId, args, SqlSession::delete);
    }

    public void batchUpdate(String namingId, List<?> args)
    {
        batchExecute(namingId, args, SqlSession::update);
    }

    /**
     * 提供DAO命名空间策略
     *
     * @return 命名空间策略
     */
    protected INamespacePolicy provideNamespacePolicy()
    {
        return new DAOClassNamePolicy(getClass());
    }

    @PostConstruct
    public void initNamespace()
    {
        if (namespaceEnabled)
        {
            namespace = provideNamespacePolicy().namespace();
        }
    }

    private String namingId(String namingId)
    {
        return namespaceEnabled ? namespace + '.' + namingId : namingId;
    }
}
